﻿namespace ACCOUNTING.Encryption
{
    using Microsoft.VisualBasic.CompilerServices;
    using System;
    using System.IO;
    using System.Security;
    using System.Security.Cryptography;
    using System.Security.Principal;
    using System.Text;

    public class Asymmetric
    {
        private const string _ElementCoefficient = "InverseQ";
        private const string _ElementExponent = "Exponent";
        private const string _ElementModulus = "Modulus";
        private const string _ElementParent = "RSAKeyValue";
        private const string _ElementPrimeExponentP = "DP";
        private const string _ElementPrimeExponentQ = "DQ";
        private const string _ElementPrimeP = "P";
        private const string _ElementPrimeQ = "Q";
        private const string _ElementPrivateExponent = "D";
        private const string _KeyCoefficient = "PrivateKey.InverseQ";
        private string _KeyContainerName;
        private const string _KeyExponent = "PublicKey.Exponent";
        private const string _KeyModulus = "PublicKey.Modulus";
        private const string _KeyPrimeExponentP = "PrivateKey.DP";
        private const string _KeyPrimeExponentQ = "PrivateKey.DQ";
        private const string _KeyPrimeP = "PrivateKey.P";
        private const string _KeyPrimeQ = "PrivateKey.Q";
        private const string _KeyPrivateExponent = "PrivateKey.D";
        private int _KeySize;
        private RSACryptoServiceProvider _rsa;
        private bool _UseMachineKeystore;

        public Asymmetric()
        {
            this._KeyContainerName = "Encryption.AsymmetricEncryption.DefaultContainerName";
            this._UseMachineKeystore = true;
            this._KeySize = 0x400;
            this._rsa = this.GetRSAProvider();
        }

        public Asymmetric(int keySize)
        {
            this._KeyContainerName = "Encryption.AsymmetricEncryption.DefaultContainerName";
            this._UseMachineKeystore = true;
            this._KeySize = 0x400;
            this._KeySize = keySize;
            this._rsa = this.GetRSAProvider();
        }

        public Data Decrypt(Data encryptedData)
        {
            PrivateKey privateKey = new PrivateKey();
            privateKey.LoadFromConfig();
            return this.Decrypt(encryptedData, privateKey);
        }

        public Data Decrypt(Data encryptedData, PrivateKey PrivateKey)
        {
            this._rsa.ImportParameters(PrivateKey.ToParameters());
            return this.DecryptPrivate(encryptedData);
        }

        public Data Decrypt(Data encryptedData, string PrivateKeyXML)
        {
            this.LoadKeyXml(PrivateKeyXML, true);
            return this.DecryptPrivate(encryptedData);
        }

        private Data DecryptPrivate(Data encryptedData)
        {
            return new Data(this._rsa.Decrypt(encryptedData.Bytes, false));
        }

        public Data Encrypt(Data d)
        {
            PublicKey defaultPublicKey = this.DefaultPublicKey;
            return this.Encrypt(d, defaultPublicKey);
        }

        public Data Encrypt(Data d, PublicKey publicKey)
        {
            this._rsa.ImportParameters(publicKey.ToParameters());
            return this.EncryptPrivate(d);
        }

        public Data Encrypt(Data d, string publicKeyXML)
        {
            this.LoadKeyXml(publicKeyXML, false);
            return this.EncryptPrivate(d);
        }

        private Data EncryptPrivate(Data d)
        {
            Data data;
            try
            {
                data = new Data(this._rsa.Encrypt(d.Bytes, false));
            }
            catch (CryptographicException exception1)
            {
                ProjectData.SetProjectError(exception1);
                CryptographicException inner = exception1;
                if (inner.Message.ToLower().IndexOf("bad length") > -1)
                {
                    throw new CryptographicException("Your data is too large; RSA encryption is designed to encrypt relatively small amounts of data. The exact byte limit depends on the key size. To encrypt more data, use symmetric encryption and then encrypt that symmetric key with asymmetric RSA encryption.", inner);
                }
                throw;
                ProjectData.ClearProjectError();
            }
            return data;
        }

        public void GenerateNewKeyset(ref PublicKey publicKey, ref PrivateKey privateKey)
        {
            string str=String.Empty;
            string str2 = String.Empty;
            this.GenerateNewKeyset(ref str2, ref str);
            publicKey = new PublicKey(str2);
            privateKey = new PrivateKey(str);
        }

        public void GenerateNewKeyset(ref string publicKeyXML, ref string privateKeyXML)
        {
            RSA rsa = RSA.Create();
            publicKeyXML = rsa.ToXmlString(false);
            privateKeyXML = rsa.ToXmlString(true);
        }

        private RSACryptoServiceProvider GetRSAProvider()
        {
            CspParameters parameters=null;
            RSACryptoServiceProvider provider=null;
            RSACryptoServiceProvider provider2=null;
            try
            {
                parameters = new CspParameters {
                    KeyContainerName = this._KeyContainerName
                };
                provider2 = new RSACryptoServiceProvider(this._KeySize, parameters) {
                    PersistKeyInCsp = false
                };
                RSACryptoServiceProvider.UseMachineKeyStore = true;
                provider = provider2;
            }
            catch (CryptographicException exception1)
            {
                ProjectData.SetProjectError(exception1);
                CryptographicException innerException = exception1;
                if (innerException.Message.ToLower().IndexOf("csp for this implementation could not be acquired") > -1)
                {
                    throw new Exception(@"Unable to obtain Cryptographic Service Provider. Either the permissions are incorrect on the 'C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys' folder, or the current security context '" + WindowsIdentity.GetCurrent().Name + "' does not have access to this folder.", innerException);
                }
                throw;
                ProjectData.ClearProjectError();
            }
            finally
            {
                if (provider2 != null)
                {
                    provider2 = null;
                }
                if (parameters != null)
                {
                    parameters = null;
                }
            }
            return provider;
        }

        private void LoadKeyXml(string keyXml, bool isPrivate)
        {
            try
            {
                this._rsa.FromXmlString(keyXml);
            }
            catch (XmlSyntaxException exception1)
            {
                string str;
                ProjectData.SetProjectError(exception1);
                XmlSyntaxException inner = exception1;
                if (isPrivate)
                {
                    str = "private";
                }
                else
                {
                    str = "public";
                }
                throw new XmlSyntaxException(string.Format("The provided {0} encryption key XML does not appear to be valid.", str), inner);
                ProjectData.ClearProjectError();
            }
        }

        public PrivateKey DefaultPrivateKey
        {
            get
            {
                PrivateKey key2 = new PrivateKey();
                key2.LoadFromConfig();
                return key2;
            }
        }

        public PublicKey DefaultPublicKey
        {
            get
            {
                PublicKey key2 = new PublicKey();
                key2.LoadFromConfig();
                return key2;
            }
        }

        public string KeyContainerName
        {
            get
            {
                return this._KeyContainerName;
            }
            set
            {
                this._KeyContainerName = value;
            }
        }

        public int KeySizeBits
        {
            get
            {
                return this._rsa.KeySize;
            }
        }

        public int KeySizeMaxBits
        {
            get
            {
                return this._rsa.LegalKeySizes[0].MaxSize;
            }
        }

        public int KeySizeMinBits
        {
            get
            {
                return this._rsa.LegalKeySizes[0].MinSize;
            }
        }

        public int KeySizeStepBits
        {
            get
            {
                return this._rsa.LegalKeySizes[0].SkipSize;
            }
        }

        public class PrivateKey
        {
            public string Coefficient;
            public string Exponent;
            public string Modulus;
            public string PrimeExponentP;
            public string PrimeExponentQ;
            public string PrimeP;
            public string PrimeQ;
            public string PrivateExponent;

            public PrivateKey()
            {
            }

            public PrivateKey(string keyXml)
            {
                this.LoadFromXml(keyXml);
            }

            public void ExportToConfigFile(string strFilePath)
            {
                StreamWriter writer = new StreamWriter(strFilePath, false);
                writer.Write(this.ToConfigSection());
                writer.Close();
            }

            public void ExportToXmlFile(string filePath)
            {
                StreamWriter writer = new StreamWriter(filePath, false);
                writer.Write(this.ToXml());
                writer.Close();
            }

            public void LoadFromConfig()
            {
                this.Modulus = ACCOUNTING.Encryption.Utils.GetConfigString("PublicKey.Modulus", true);
                this.Exponent = ACCOUNTING.Encryption.Utils.GetConfigString("PublicKey.Exponent", true);
                this.PrimeP = ACCOUNTING.Encryption.Utils.GetConfigString("PrivateKey.P", true);
                this.PrimeQ = ACCOUNTING.Encryption.Utils.GetConfigString("PrivateKey.Q", true);
                this.PrimeExponentP = ACCOUNTING.Encryption.Utils.GetConfigString("PrivateKey.DP", true);
                this.PrimeExponentQ = ACCOUNTING.Encryption.Utils.GetConfigString("PrivateKey.DQ", true);
                this.Coefficient = ACCOUNTING.Encryption.Utils.GetConfigString("PrivateKey.InverseQ", true);
                this.PrivateExponent = ACCOUNTING.Encryption.Utils.GetConfigString("PrivateKey.D", true);
            }

            public void LoadFromXml(string keyXml)
            {
                this.Modulus = ACCOUNTING.Encryption.Utils.GetXmlElement(keyXml, "Modulus");
                this.Exponent = ACCOUNTING.Encryption.Utils.GetXmlElement(keyXml, "Exponent");
                this.PrimeP = ACCOUNTING.Encryption.Utils.GetXmlElement(keyXml, "P");
                this.PrimeQ = ACCOUNTING.Encryption.Utils.GetXmlElement(keyXml, "Q");
                this.PrimeExponentP = ACCOUNTING.Encryption.Utils.GetXmlElement(keyXml, "DP");
                this.PrimeExponentQ = ACCOUNTING.Encryption.Utils.GetXmlElement(keyXml, "DQ");
                this.Coefficient = ACCOUNTING.Encryption.Utils.GetXmlElement(keyXml, "InverseQ");
                this.PrivateExponent = ACCOUNTING.Encryption.Utils.GetXmlElement(keyXml, "D");
            }

            public string ToConfigSection()
            {
                StringBuilder builder = new StringBuilder();
                StringBuilder builder2 = builder;
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteConfigKey("PublicKey.Modulus", this.Modulus));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteConfigKey("PublicKey.Exponent", this.Exponent));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteConfigKey("PrivateKey.P", this.PrimeP));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteConfigKey("PrivateKey.Q", this.PrimeQ));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteConfigKey("PrivateKey.DP", this.PrimeExponentP));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteConfigKey("PrivateKey.DQ", this.PrimeExponentQ));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteConfigKey("PrivateKey.InverseQ", this.Coefficient));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteConfigKey("PrivateKey.D", this.PrivateExponent));
                builder2 = null;
                return builder.ToString();
            }

            public RSAParameters ToParameters()
            {
                return new RSAParameters { Modulus = Convert.FromBase64String(this.Modulus), Exponent = Convert.FromBase64String(this.Exponent), P = Convert.FromBase64String(this.PrimeP), Q = Convert.FromBase64String(this.PrimeQ), DP = Convert.FromBase64String(this.PrimeExponentP), DQ = Convert.FromBase64String(this.PrimeExponentQ), InverseQ = Convert.FromBase64String(this.Coefficient), D = Convert.FromBase64String(this.PrivateExponent) };
            }

            public string ToXml()
            {
                StringBuilder builder = new StringBuilder();
                StringBuilder builder2 = builder;
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlNode("RSAKeyValue", false));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlElement("Modulus", this.Modulus));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlElement("Exponent", this.Exponent));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlElement("P", this.PrimeP));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlElement("Q", this.PrimeQ));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlElement("DP", this.PrimeExponentP));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlElement("DQ", this.PrimeExponentQ));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlElement("InverseQ", this.Coefficient));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlElement("D", this.PrivateExponent));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlNode("RSAKeyValue", true));
                builder2 = null;
                return builder.ToString();
            }
        }

        public class PublicKey
        {
            public string Exponent;
            public string Modulus;

            public PublicKey()
            {
            }

            public PublicKey(string KeyXml)
            {
                this.LoadFromXml(KeyXml);
            }

            public void ExportToConfigFile(string filePath)
            {
                StreamWriter writer = new StreamWriter(filePath, false);
                writer.Write(this.ToConfigSection());
                writer.Close();
            }

            public void ExportToXmlFile(string filePath)
            {
                StreamWriter writer = new StreamWriter(filePath, false);
                writer.Write(this.ToXml());
                writer.Close();
            }

            public void LoadFromConfig()
            {
                this.Modulus = ACCOUNTING.Encryption.Utils.GetConfigString("PublicKey.Modulus", true);
                this.Exponent = ACCOUNTING.Encryption.Utils.GetConfigString("PublicKey.Exponent", true);
            }

            public void LoadFromXml(string keyXml)
            {
                this.Modulus = ACCOUNTING.Encryption.Utils.GetXmlElement(keyXml, "Modulus");
                this.Exponent = ACCOUNTING.Encryption.Utils.GetXmlElement(keyXml, "Exponent");
            }

            public string ToConfigSection()
            {
                StringBuilder builder = new StringBuilder();
                StringBuilder builder2 = builder;
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteConfigKey("PublicKey.Modulus", this.Modulus));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteConfigKey("PublicKey.Exponent", this.Exponent));
                builder2 = null;
                return builder.ToString();
            }

            public RSAParameters ToParameters()
            {
                return new RSAParameters { Modulus = Convert.FromBase64String(this.Modulus), Exponent = Convert.FromBase64String(this.Exponent) };
            }

            public string ToXml()
            {
                StringBuilder builder = new StringBuilder();
                StringBuilder builder2 = builder;
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlNode("RSAKeyValue", false));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlElement("Modulus", this.Modulus));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlElement("Exponent", this.Exponent));
                builder2.Append(ACCOUNTING.Encryption.Utils.WriteXmlNode("RSAKeyValue", true));
                builder2 = null;
                return builder.ToString();
            }
        }
    }
}

